/**
	@file   Unicode.h
	@date   2010/09/25
	@author sang-soo kim
	@brief  a converter between euc-kr, utf8, utf16 and utf32

*/

#if !defined(__KRWS_UNICODE_H__)
#define __KRWS_UNICODE_H__
#pragma once


#include <stdio.h>
#include <stdint.h>
#include <iconv.h>
#include <string.h>
#include <errno.h>
#include <stdarg.h>
#include <stdlib.h>

/*
uint16_t han_cho[] =
{
	0x1100, 0x1101, 0x1102, 0x1103, 0x1104, 0x1105, 0x1106, 0x1107, 0x1108, 0x1109, 0x110a, 0x110b, 0x110c, 0x110d, 0x110e, 0x110f,
	0x1110, 0x1111, 0x1112
};
uint16_t han_jung[] =
{
	        0x1161, 0x1162, 0x1163, 0x1164, 0x1165, 0x1166, 0x1167, 0x1168, 0x1169, 0x116a, 0x116b, 0x116c, 0x116d, 0x116e, 0x116f,
	0x1170, 0x1171, 0x1172, 0x1173, 0x1174, 0x1175
};
uint16_t han_jong[] =
{
	                                                        0x11a7, 0x11a8, 0x11a9, 0x11aa, 0x11ab, 0x11ac, 0x11ad, 0x11ae, 0x11af,
	0x11b0, 0x11b1, 0x11b2, 0x11b3, 0x11b4, 0x11b5, 0x11b6, 0x11b7, 0x11b8, 0x11b9, 0x11ba, 0x11bb, 0x11bc, 0x11bd, 0x11be, 0x11bf,
	0x11c0, 0x11c1, 0x11c2
};
*/
class Unicode
{
public:
	static inline int convert( const char * from_char_set, const char * to_char_set,  char *out_ptr, int dstmax,  char *in_ptr, int srclen )
	{
		int wrbytes, tmpidx;
		size_t cvtsrclen, cvtdstlen;//, cvtlen;
		char *tmp_out_ptr;
		int i=0;

		iconv_t iconv_a2b = iconv_open( to_char_set, from_char_set);

		if(iconv_a2b == (iconv_t)(-1))
			return -1;
		memset( out_ptr, 0, dstmax );

		cvtsrclen = srclen;

		tmp_out_ptr = out_ptr;
		cvtdstlen = dstmax;

		int  cvtlen = iconv( iconv_a2b, &in_ptr, &cvtsrclen, &tmp_out_ptr, &cvtdstlen );

		if (cvtlen == -1)
		{
			fprintf(stderr, "Error(%s) in converting characters <-- %d\n",  strerror(errno), errno);

			iconv_close( iconv_a2b  );
			exit(8);
		}

		iconv_close( iconv_a2b );

		return cvtlen;
	}
	static inline int convert_utf8_to_utf32( const char * in_ptr, char * out_ptr )
	{
		int rc=0;
		int len= strlen( in_ptr)*4;

		rc = convert("UTF-8","UTF-32", out_ptr, len,(char*) in_ptr, strlen(in_ptr) );

		return rc;
	}

	
	static inline int convert_utf8_to_utf16( const char * in_ptr, char * out_ptr )
	{
		int rc=0;
		int len= strlen( in_ptr)*4;

		rc = convert("UTF-8","UTF-16", out_ptr, len,(char*) in_ptr, strlen(in_ptr) );
		return rc;
	}
	static inline int utf32_length(const  char * in_ptr,  bool show_byte=false)
	{
		int length=-1;
		unsigned int * p = ( unsigned int * ) in_ptr;

		int i=0;
		while(1)
		{
			if( *p == 0x0000 ) break;
			if( *p == 0x000d && *(p+1) == 0x000a  ) break;

			if( show_byte)  printf("%x, ", (unsigned int) *p);

			length++;
			p++;

			if( i>10) break;

		}
		if( show_byte) printf("\n");
		return length;

	}
	static inline int utf16_length(const  char * in_ptr, bool show_byte=false)
	{
		int i=0, length=-1;
		unsigned short * p = ( unsigned short * ) in_ptr;

		if(in_ptr == NULL)	return -1; 

		while(1)
		{
		    if( *p == 0x00 ) break;

		    if( *p == 0x0d && *(p+1) == 0x0a  ) break;

			if( show_byte) 	printf("%d:%x, ", i++,(unsigned int) *p);

			length++;
			p++;
		}
		if( show_byte) printf("\n");
		return length;
	}
	static inline int convert_utf32_to_utf8( const char * in_ptr, char * out_ptr )
	{
		int rc=0;
		int len= utf32_length( in_ptr );

		rc = convert("UTF-32","UTF-8", out_ptr, (len+1) *4 +1  ,(char*) in_ptr, (len+1) *4 );
		return rc;

	}
	static inline int convert_utf16_to_utf8( const char * in_ptr, char * out_ptr )
	{
		int rc=0;
		int len= utf16_length( in_ptr );

		rc = convert("UTF-16","UTF-8", out_ptr, (len+1) *4 +1  ,(char*) in_ptr, (len+1) *4 );

		return rc;

	}

	static inline int convert_utf8_to_cp949( const char * in_ptr, char* out_ptr )
	{
		int rc=0;
		int len= strlen( in_ptr);

		rc = convert("UTF-8","cp949", out_ptr, len,(char*) in_ptr, strlen(in_ptr) );

		return rc;
	}


	static inline int combine( uint16_t * in, uint16_t * out )
	{
		uint16_t w_char = 0x0000, pre, middle, post;

		try{
			pre = * in++;
			middle = * in++;
			post = * in++;
		} catch( ...)
		{
			return -1;
		}

		if ( pre < 0x1100 || pre > 0x1112) return -1;
		if ( middle < 0x1161 || middle > 0x1175) return -1;
		if ( post < 0x11a7 || post > 0x11c2) return -1;

		pre =  pre - 0x1100 ;
		middle = middle - 0x1161;
		post = post - 0x11a7;

		try{
			*out = ( ( ( pre * 21 ) + middle ) * 28 ) + post + 0xAC00 ; 
		} catch ( ... )
		{
			return -1;
		}
		
		return 0;
	}
	static inline int parse( uint16_t  in_str, uint16_t * out_arr )
	{
		uint16_t han_cho[] =
		{
		    0x1100, 0x1101, 0x1102, 0x1103, 0x1104, 0x1105, 0x1106, 0x1107, 0x1108, 0x1109, 0x110a, 0x110b, 0x110c, 0x110d, 0x110e, 0x110f,
		    0x1110, 0x1111, 0x1112
		};
		uint16_t han_jung[] =
		{
    		        0x1161, 0x1162, 0x1163, 0x1164, 0x1165, 0x1166, 0x1167, 0x1168, 0x1169, 0x116a, 0x116b, 0x116c, 0x116d, 0x116e, 0x116f,
		    0x1170, 0x1171, 0x1172, 0x1173, 0x1174, 0x1175
		};
		uint16_t han_jong[] =
		{
		                                                            0x11a7, 0x11a8, 0x11a9, 0x11aa, 0x11ab, 0x11ac, 0x11ad, 0x11ae, 0x11af,
		    0x11b0, 0x11b1, 0x11b2, 0x11b3, 0x11b4, 0x11b5, 0x11b6, 0x11b7, 0x11b8, 0x11b9, 0x11ba, 0x11bb, 0x11bc, 0x11bd, 0x11be, 0x11bf,
		    0x11c0, 0x11c1, 0x11c2
		};

		uint16_t w_char = 0x0000, pre, middle, post;

		if(  in_str < 0xac00 || in_str > 0xd7a3)
			return -1;

		w_char =  in_str - 0xac00;

		post = w_char % 28;
		middle = ((w_char-post) / 28)%21;
		pre = (( w_char-post)/28)/21;;

		try {
			*out_arr = han_cho[ pre ]; out_arr ++;
			*out_arr = han_jung[ middle ]; out_arr ++;
			*out_arr = han_jong[ post]; out_arr ++;	
		} catch ( ... )
		{
			return -1;
		}
		return 0;
	}

	static inline int convert_cp949_to_utf8( const char * in_ptr, char* out_ptr )
	{
		int rc;
		int len= strlen( in_ptr) *2;

		rc = convert("cp949","UTF-8", out_ptr, len,(char*) in_ptr, strlen(in_ptr) );

		return rc;
	}
};


#endif






